/*
Copyright (c) 2009, Dan Hagerstrand and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of Cirrus Creative nor the names of its
  contributors may be used to endorse or promote products derived from this
  software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef BENG_SCENE_H
#define BENG_SCENE_H

#include <vector>

#include "BengFixedPoint.h"
#include "Camera.h"
#include "CString.h"
#include "Layer.h"
#include "Manager.h"
#include "System.h"

class BengLayer;

/// The BengScene class describes what is referred to as a 'scene', where all the action in a game takes place. A scene might represent a game level, a menu,
/// a title screen, or anything else that represents a "section" of the game. A BengScene can contain BengLayer objects, and those layers can contain BengObject
/// instances. Since you can have multiple BengScene instances at a time, you could make use of several techniques, including preloading, and virtual television
/// screens within the scene that display what is going on in another scene.
///
/// The BengSystem object will always have one "main" scene which is handled automatically and by default will cover up the entire screen. This means you can use
/// this to switch dynamically between different maps without inducing any loading times (although the scene will need to have been loaded previously, an operation
/// that will take up more memory).

class BengScene {
    friend class BengLayer;
    friend class BengObject;
    friend class BengIGfx;
    friend class BengCamera;

    private:

    int layersForDeletion_;
    char deleteAll_;

    void purgeLayers_(void);

    protected:

    BengSystem *system;

    BengCString sceneName;
    std::vector<BengLayer*> layerList;
    std::vector<BengLayer*>::iterator layerIterator;

    BengManager<std::vector<BengCamera*>, BengCamera> *cameraManager;

    unsigned int mainLayer;

    public:

    /// Creates a BengScene object. It will be pretty useless in its initial state, as it initializes to nothingness. You will need to add
    /// layers and give the scene a name.
    BengScene(void);
    /// Removes the scene from the game, destroying any attached layers and any objects that might be contained in those layers.
    ~BengScene(void);

    /// Retrieves the BengSystem object that this scene is attached to, if any.
    BengSystem *getSystem(void);
    // TODO: Fixup with derivation of storage container class so that this funciton can be removed.
    void attachToSystem(BengSystem *parentSystem);

    /// Returns the name of this scene as previously set using setName(). The name can be seen in the standard output and logging, as well as
    /// user-defined areas such as for title cards.
    const char *getName(void);
    /// Sets the scene's name to the C string 'name'. The name can be seen in the standard output and logging, as well as
    /// user-defined areas such as for title cards.
    void setName(const char *name);

    /// Takes an instantiated BengLayer and attaches it to the scene, adding it to the internal layers list. For the rest of the layer's lifetime,
    /// it will be managed by the scene and will rely on it for safe deletion. The basic code for attaching a layer might look like:
    ///
    /// BengLayer *layer = new BengLayer(32, 32);\n
    /// layer->setTileSize(32, 32);\n
    /// scene->addLayer(layer);
    void addLayer(BengLayer *layer);
    /// Marks all attached layers for deletion, and physically removes them after all layers have been processed, to avoid unsafe deletion.
    void clearLayers(void);
    /// Retrieves the attached BengLayer at index layernum. Keep in mind that this method will become unreliable if at any time you decide to delete
    /// any attached layers, because the indexes of the proceeding layers will change.
    BengLayer *getLayer(int layernum);
    /// Retrieves the total number of attached layers in this scene, minus any layers that are marked for deletion.
    int getNumLayers(void);

    void addCamera(BengCamera *camera);
    void releaseCamera(BengCamera *camera);

    BengCamera *iterateCamera(void);

    void process(void);

};

#endif
